home *** CD-ROM | disk | FTP | other *** search
/ Aminet 8 / Aminet 8 (1995)(GTI - Schatztruhe)[!][Oct 1995].iso / Aminet / mus / play / tracker_4_31.lzh / tracker / Amiga / ui.c < prev    next >
C/C++ Source or Header  |  1995-05-11  |  16KB  |  648 lines

  1. /* amiga/ui.c 
  2.     vi:ts=3 sw=3:
  3.  */
  4.  
  5. /* $Id: ui.c,v 1.23 1995/05/11 12:16:16 espie Exp espie $
  6.  * $Log: ui.c,v $
  7.  * Revision 1.23  1995/05/11  12:16:16  espie
  8.  * Minor changes.
  9.  *
  10.  * Revision 1.22  1995/02/14  16:51:22  espie
  11.  * *** empty log message ***
  12.  *
  13.  * Revision 1.21  1995/02/13  22:05:42  espie
  14.  * Changed version number.
  15.  *
  16.  * Revision 1.20  1995/01/13  13:31:35  espie
  17.  * *** empty log message ***
  18.  *
  19.  * Revision 1.20  1994/06/22  21:54:12  Espie
  20.  * Split across other files.
  21.  * File requester !
  22.  * Added pause gadget.
  23.  * Uncentralized event handling using event management functions.
  24.  * Changed name to ui_win, added Show gadget.
  25.  * better coding for gadgets.
  26.  * Nasty bug with info: did not close the file properly.
  27.  * Fully working asynchronous interface.
  28.  * User feedback.
  29.  * Added missing autoinit
  30.  * Removed some typecasts.
  31.  * info facility.
  32.  * scroll post-synchronized output.
  33.  * notice.
  34.  * Cursor handling.
  35.  * Used of discard_buffer for premature ending.
  36.  * Mostly working.
  37.  * Just dies with a guru.
  38.  * Plus timing problems at start.
  39.  */
  40.  
  41. #include <proto/intuition.h>
  42. #include <proto/gadtools.h>
  43. #include <proto/exec.h>
  44. #include <dos/dos.h>
  45. #include <intuition/intuitionbase.h>
  46.  
  47. #include "defs.h"
  48. #include "extern.h"
  49. #include "amiga/amiga.h"
  50. #include "tags.h"
  51. #include "prefs.h"
  52.  
  53. extern char *VERSION;
  54. ID("$Id: ui.c,v 1.23 1995/05/11 12:16:16 espie Exp espie $")
  55.  
  56. XT unsigned int inhibit_output;
  57.  
  58. LOCAL void init_ui(void);
  59. LOCAL void do_set_current(VALUE current);
  60. LOCAL void handle_ui_window(GENERIC nothing);
  61.  
  62. LOCAL void (*INIT)(void) = init_ui;
  63.  
  64.  
  65. /* These two variables memorize where we actually are in
  66.  * the current song
  67.  */
  68. LOCAL int current_pattern;
  69.  
  70. #define SMALL_DELAY 3         /* in seconds */
  71.  
  72. /* And these when stuff last changed */
  73. LOCAL ULONG pattern_change_seconds, pattern_change_micros,
  74. song_change_seconds, song_change_micros;
  75.  
  76.  
  77. /* The basic user interface (a simple window) */
  78.  
  79. struct IntuitionBase *IntuitionBase = 0;
  80. struct GfxBase *GfxBase = 0;
  81. LOCAL struct Library *GadtoolsBase = 0;
  82. LOCAL struct Window *ui_win;
  83.  
  84. void set_busy_pointer(BOOL maybe)
  85.    {
  86.    if (IntuitionBase->LibNode.lib_Version < 39)
  87.       return;
  88.    if (ui_win)
  89.       SetWindowPointer(ui_win, WA_BusyPointer, maybe, WA_PointerDelay, TRUE, TAG_DONE, 0);
  90.    }
  91.  
  92. /* for asynchronous easy requests */
  93. LOCAL struct Window *notice_win = 0;
  94.  
  95.    /* for computing length */
  96. LOCAL struct IntuiText it;
  97.  
  98. #define SHIFT 4
  99. #define SPACEX 10
  100. #define SPACEY 4
  101.  
  102. #define WINDOW_TITLE "Experiment IV "        /* the space in case the font is italic */
  103.  
  104. LOCAL struct NewGadget template =
  105.    {
  106.    0, 0,
  107.    0, 0,
  108.    NULL,
  109.    0,
  110.    0,       /* gadget ID */
  111.    0,
  112.    NULL,
  113.    NULL
  114.    };
  115.  
  116. LOCAL struct NewMenu menu_template[] =
  117.    {
  118.    {NM_TITLE,  "Project",        0, 0, 0, 0},
  119.       {NM_ITEM,   "Load song...",   0, 0, 0, (void *)4},
  120.       {NM_ITEM,   "About...",       0, 0, 0, (void *)1},
  121.       {NM_ITEM,   "Quit",           0, 0, 0, (void *)2},
  122.    {NM_TITLE,  "Settings",       0, 0, 0, 0},
  123.          /* WARNING: check item_number if you add menu entries */
  124.       {NM_ITEM,   "PAL",            0, CHECKIT, 6, (void *)50},
  125.       {NM_ITEM,   "NTSC",           0, CHECKIT, 5, (void *)60},
  126.       {NM_ITEM,   "Custom",         0, CHECKIT, 3, (void *)3},
  127.    {NM_END,    0,                0, 0, 0, 0}
  128.    };
  129.  
  130. LOCAL struct Menu *menu = 0;
  131.  
  132. LOCAL APTR vi;
  133. LOCAL struct Screen *pub = 0;
  134. LOCAL struct Gadget *glist, *title_gad, *pattern_gad, *total_gad;
  135.  
  136. /* we precisely have seven gadgets */
  137. #define MAX_GADGET 6
  138.  
  139. /* all labelled with strings */
  140. LOCAL char *label[MAX_GADGET + 1] =
  141.    {
  142.    "|<",
  143.    "<<",
  144.    "//",
  145.    ">>", 
  146.    ">|",
  147.    "?",
  148.    "000",
  149.    };
  150.  
  151. #define G_NEXT 4
  152. #define G_RESTART_PREVIOUS 0
  153. #define G_REWIND 1
  154. #define G_FF 3
  155. #define G_SHOW 5
  156. #define G_PAUSE 2
  157. LOCAL struct ext_message *restart_msg = NULL;
  158.  
  159. LOCAL void cleanup_ui()
  160.    {
  161.    if (restart_msg)
  162.       {
  163.       send(restart_msg, TYPE_UNPAUSE);
  164.       restart_msg = 0;
  165.       }
  166.    if (ui_win)
  167.       {
  168.       remove_signal_handler(ui_win->UserPort->mp_SigBit);
  169.       SetWindowTitles(ui_win, 0, 0);
  170.       ClearMenuStrip(ui_win);
  171.       CloseWindow(ui_win);
  172.       ui_win = 0;
  173.       }
  174.    if (menu)
  175.       FreeMenus(menu);
  176.    if (glist)
  177.       FreeGadgets(glist);
  178.    if (vi)
  179.       FreeVisualInfo(vi);
  180.    if (pub)
  181.       UnlockPubScreen(NULL, pub);
  182.    while (notice_win)
  183.       await_events();
  184.    if (GfxBase)
  185.       CloseLibrary(GfxBase);
  186.    if (IntuitionBase)
  187.       CloseLibrary(IntuitionBase);
  188.    if (GadtoolsBase)
  189.       CloseLibrary(GadtoolsBase);
  190.    }
  191.    
  192.  
  193. LOCAL void init_ui(void)
  194.    {
  195.    struct Gadget *gad;
  196.    int i;
  197.    int max_width;
  198.    int width, height;
  199.    UWORD zoom[4];
  200.  
  201.    at_end(cleanup_ui);
  202.    IntuitionBase = OpenLibrary("intuition.library", 37);
  203.    if (!IntuitionBase)
  204.       end_all("No Intuition");
  205.    GadtoolsBase = OpenLibrary("gadtools.library", 37);
  206.    if (!GadtoolsBase)
  207.       end_all("No gadtools");
  208.    GfxBase = OpenLibrary("graphics.library", 37);
  209.    if (!GfxBase)
  210.       end_all("No graphics");
  211.    pub = LockPubScreen(NULL);
  212.    if (!pub)
  213.       end_all("No pubscreen");
  214.    vi = GetVisualInfo(pub, TAG_END);
  215.    if (!vi)
  216.       end_all("No VI");
  217.       {
  218.       int item_number;
  219.  
  220.       switch(get_pref_scalar(PREF_SPEED))
  221.          {
  222.       case 50:
  223.          item_number = 5; break;
  224.       case 60:
  225.          item_number = 6; break;
  226.       default:
  227.          item_number = 7; break;
  228.          }
  229.       menu_template[item_number].nm_Flags |= CHECKED;
  230.       }
  231.    menu = CreateMenus(menu_template, GTMN_FrontPen, BARDETAILPEN, TAG_END);
  232.    if (!menu)
  233.       end_all("No menus");
  234.    if (!LayoutMenus(menu, vi, TAG_END))
  235.       end_all("Menus badly formed");
  236.       
  237.       /* now to create the gadgets */
  238.       /* Compute max width/height according to the font */
  239.    it.ITextFont = pub->Font;
  240.    template.ng_TextAttr = pub->Font;
  241.    
  242.    max_width = 0;
  243.    for (i = 0; i < MAX_GADGET + 1; i++)
  244.       {
  245.       it.IText = label[i];  
  246.       width = IntuiTextLength(&it);
  247.       if (width > max_width)
  248.          max_width = width;
  249.       }
  250.     
  251.    max_width += SPACEX;
  252.    template.ng_Width = max_width;     
  253.    template.ng_Height = pub->Font->ta_YSize + SPACEY;
  254.  
  255.       /* set up Top/Left Edge of initial gadget according to Wbar */
  256.    template.ng_TopEdge = pub->WBorTop + 1 + 2 * template.ng_Height + SHIFT;
  257.    template.ng_LeftEdge = pub->WBorLeft + SHIFT; 
  258.  
  259.    gad = CreateContext(&glist);
  260.    if (!gad)
  261.       end_all("No context");
  262.    template.ng_VisualInfo = vi;
  263.       /* lay out gadgets */
  264.    for (i = 0; i < MAX_GADGET; i++)
  265.       {
  266.       template.ng_GadgetText = label[i];
  267.       gad = CreateGadget(BUTTON_KIND, gad, &template, TAG_END);
  268.       if (!gad)
  269.          end_all("Bad gadget");
  270.       template.ng_LeftEdge += template.ng_Width + SHIFT;
  271.       template.ng_GadgetID++;
  272.       }
  273.    width = template.ng_LeftEdge + pub->WBorRight;
  274.    height = template.ng_TopEdge + template.ng_Height + pub->WBorBottom + SHIFT;
  275.  
  276.       /* zoom box */
  277.    zoom[0] = ~0;
  278.    zoom[1] = ~0;
  279.    zoom[2] = width;
  280.    zoom[3] = pub->WBorTop + 1 + pub->Font->ta_YSize;
  281.  
  282.       /* title gadget */     
  283.    template.ng_GadgetText = "";
  284.    template.ng_Width = width - SHIFT - pub->WBorLeft - pub->WBorRight;
  285.    template.ng_Width -= 2 * max_width;
  286.    template.ng_TopEdge = pub->WBorTop + 1 + template.ng_Height + SHIFT;
  287.    template.ng_LeftEdge = SHIFT + pub->WBorLeft;
  288.    title_gad = gad = CreateGadget(TEXT_KIND, gad, &template, TAG_END);
  289.    if (!gad)
  290.       end_all("Bad gadget");
  291.       
  292.       /* pattern gadget */
  293.    template.ng_LeftEdge += template.ng_Width + SHIFT;
  294.    template.ng_Width = max_width;
  295.    pattern_gad = gad = CreateGadget(NUMBER_KIND, gad, &template, TAG_END);
  296.    if (!gad)
  297.       end_all("Bad gadget");
  298.  
  299.       /* total pattern */
  300.    template.ng_GadgetText = "/";
  301.    template.ng_LeftEdge += template.ng_Width + SHIFT;
  302.    total_gad = gad = CreateGadget(NUMBER_KIND, gad, &template, TAG_END);
  303.    if (!gad)
  304.       end_all("Bad gadget");
  305.    ui_win = OpenWindowTags(NULL, 
  306.       WA_Title, WINDOW_TITLE,
  307.       WA_Width, width,
  308.       WA_Height, height,
  309.       WA_MinWidth, zoom[2],
  310.       WA_MaxWidth, width,
  311.       WA_MinHeight, zoom[3],
  312.       WA_MaxHeight, height,
  313.       WA_AutoAdjust, TRUE,
  314.       WA_MouseQueue, 35,   /* we can't always answer messages */
  315.       WA_DepthGadget, TRUE,
  316.       WA_CloseGadget, TRUE,
  317.       WA_DragBar, TRUE,
  318.       WA_Zoom, zoom,
  319.       WA_Gadgets, glist,
  320.       WA_IDCMP, IDCMP_CLOSEWINDOW | BUTTONIDCMP | TEXTIDCMP | 
  321.                 IDCMP_REFRESHWINDOW | IDCMP_MENUPICK,
  322.       WA_NewLookMenus, TRUE,
  323.       WA_PubScreen, pub,
  324.       TAG_DONE, 0);
  325.    if (!ui_win)
  326.       end_all("No window");
  327.    GT_RefreshWindow(ui_win, NULL);  
  328.    SetMenuStrip(ui_win, menu);
  329.  
  330.    install_signal_handler(ui_win->UserPort->mp_SigBit, handle_ui_window, 0);
  331.    
  332.    /* build up scroll buffer stuff */
  333.    }
  334.  
  335. struct Screen *obtain_pubscreen(void)
  336.    {
  337.    INIT_ONCE;
  338.    
  339.    return pub;
  340.    }
  341.  
  342. /* Max number of input messages we can remember */
  343. #define MAX_INPUT 20
  344. LOCAL struct tag result[MAX_INPUT +1];
  345. LOCAL int i = 0;
  346.  
  347. LOCAL void handle_ui_window(GENERIC nothing)
  348.    {
  349.    struct IntuiMessage *msg;
  350.    UWORD number;
  351.    struct MenuItem *item;
  352.    int id;
  353.    VALUE temp;
  354.    
  355.    while((msg = GT_GetIMsg(ui_win->UserPort)) && i < MAX_INPUT)
  356.       switch(msg->Class)
  357.          {
  358.       case IDCMP_CLOSEWINDOW:
  359.          GT_ReplyIMsg(msg);
  360.          set_break();
  361.          break;
  362.       case IDCMP_MENUPICK:
  363.          number = msg->Code;
  364.          while (number != MENUNULL)
  365.             {
  366.             item = ItemAddress(menu, msg->Code);
  367.             switch((int)GTMENUITEM_USERDATA(item))
  368.                {
  369.             case 1:
  370.                {
  371.                char buffer[500];
  372.                sprintf(buffer,
  373. "Tracker %s (%s)\n\
  374.       by Marc Espie (Marc.Espie@ens.fr)\n\n\
  375. This is a giftware program\n\
  376. If you want, you can send me some money\n\
  377. My address is:\n\
  378.       Espie Marc\n\
  379.       60 rue du 4 septembre\n\
  380.       87100 Limoges\n\
  381.       France\n\n\
  382. For the most recent version:\n\
  383.       ftp Aminet or nic.funet.fi\0", VERSION, __DATE__);
  384.                notice(buffer);
  385.                }
  386.                break;
  387.             case 2:
  388.                item = 0;
  389.                set_break();
  390.                break;
  391.             case 4:
  392.                launch_requester();
  393.                break;
  394.             case 50:
  395.             case 60:
  396.                result[i].type = UI_SET_BPM;
  397.                result[i++].data.scalar = (int)GTMENUITEM_USERDATA(item);
  398.                set_pref_scalar(PREF_SPEED, (int)GTMENUITEM_USERDATA(item));
  399.                break;
  400.             default:
  401.                break;
  402.                }
  403.             number = item->NextSelect;
  404.             }
  405.          GT_ReplyIMsg(msg);
  406.          break;
  407.       case IDCMP_REFRESHWINDOW:
  408.          GT_ReplyIMsg(msg);
  409.          GT_BeginRefresh(ui_win);
  410.          GT_EndRefresh(ui_win, TRUE);
  411.          break;
  412.       case IDCMP_GADGETUP:
  413.          id = ((struct Gadget *)msg->IAddress)->GadgetID;
  414.          switch(id)
  415.             {
  416.          case G_NEXT:
  417.             result[i++].type = UI_NEXT_SONG;
  418.             break;
  419.          case G_RESTART_PREVIOUS:
  420.             if (msg->Seconds < song_change_seconds + SMALL_DELAY ||
  421.                 (msg->Seconds == song_change_seconds + SMALL_DELAY && 
  422.                 msg->Micros <= song_change_micros) )
  423.                 {
  424.                 result[i++].type = UI_PREVIOUS_SONG;
  425.                 break;
  426.                 }
  427.             else
  428.                {
  429.                result[i++].type = UI_RESTART;
  430.                song_change_seconds = msg->Seconds;
  431.                song_change_micros = msg->Micros;
  432.                }
  433.             break;
  434.          case G_REWIND:
  435.             result[i].type = UI_JUMP_TO_PATTERN;
  436.             result[i].data.scalar = current_pattern;
  437.             if (msg->Seconds < pattern_change_seconds + SMALL_DELAY ||
  438.                 (msg->Seconds == pattern_change_seconds + SMALL_DELAY && 
  439.                 msg->Micros <= pattern_change_micros) )
  440.                 result[i].data.scalar--;
  441.                    /* give some immediate feedback to the user */
  442.             temp.scalar = result[i].data.scalar;
  443.             do_set_current(temp);
  444.                 i++;
  445.             break;
  446.          case G_FF:
  447.             result[i].type = UI_JUMP_TO_PATTERN;
  448.             result[i].data.scalar = current_pattern + 1;
  449.                   /* give some immediate feedback to the user */
  450.             temp.scalar = result[i].data.scalar;
  451.             do_set_current(temp);
  452.             i++;
  453.             break;
  454.          case G_SHOW:
  455.             set_pref_scalar(PREF_SHOW, TRUE);
  456.             break;
  457.          case G_PAUSE:
  458.             if (restart_msg)
  459.                {
  460.                send(restart_msg, TYPE_UNPAUSE);
  461.                restart_msg = 0;
  462.                }
  463.             else
  464.                {
  465.                struct ext_message *msg;
  466.                
  467.                msg = obtain_message();
  468.                restart_msg = obtain_message();
  469.                send(msg, TYPE_PAUSE);
  470.                }
  471.             }
  472.          GT_ReplyIMsg(msg);
  473.          break;
  474.       default:
  475.          GT_ReplyIMsg(msg);
  476.          }
  477.    }
  478.  
  479.  
  480. void requested_file(struct amiganame *name)
  481.    {
  482.    result[i].data.pointer = name;
  483.    result[i++].type = UI_LOAD_SONG;
  484.    }
  485.  
  486.    
  487. struct tag *get_ui()
  488.    {
  489.  
  490.    INIT_ONCE
  491.  
  492.    if (checkbrk())
  493.       result[i++].type = UI_QUIT;
  494.    
  495.    result[i].type = TAG_END;
  496.    
  497.    i = 0;
  498.    return result;
  499.    }
  500.  
  501.  
  502. void song_title(char *s)
  503.    {
  504.    static char title[25];
  505.  
  506.    INIT_ONCE;
  507.  
  508.    strncpy(title, s, 25);
  509.    if (ui_win)
  510.       GT_SetGadgetAttrs(title_gad, ui_win, 0, GTTX_Text, title, TAG_END);
  511.    /* stamp the time we changed the song */
  512.    CurrentTime(&song_change_seconds, &song_change_micros);
  513.    }
  514.  
  515. void status(char *s)   
  516.    {
  517.    INIT_ONCE;
  518.    
  519.    SetWindowTitles(ui_win, s ? s : WINDOW_TITLE, -1);
  520.    }
  521.  
  522. /* hook to change current pattern */
  523. LOCAL void do_set_current(VALUE p)
  524.    {
  525.    if (!inhibit_output)
  526.       {
  527.       INIT_ONCE;
  528.       if (ui_win)
  529.          GT_SetGadgetAttrs(pattern_gad, ui_win, 0, GTNM_Number, p.scalar, TAG_END);
  530.       }
  531.    current_pattern = p.scalar;
  532.    if (get_pref_scalar(PREF_SHOW))
  533.       add_scroller(NULL);
  534.    /* stamp the time we changed the pattern */
  535.    CurrentTime(&pattern_change_seconds, &pattern_change_micros);
  536.    }
  537.  
  538. /* hook to change current pattern total */
  539. LOCAL void do_set_total(VALUE p)
  540.     {
  541.     INIT_ONCE;
  542.    if (ui_win)
  543.       GT_SetGadgetAttrs(total_gad, ui_win, 0, GTNM_Number, p.scalar, TAG_END);
  544.     }
  545.  
  546. void display_pattern(int current, int total, int real)
  547.    {
  548.    struct ext_message *msg;
  549.  
  550.    INIT_ONCE 
  551.  
  552.    msg = obtain_message();
  553.     msg->data.hook.func = do_set_total;
  554.    msg->data.hook.p.scalar = total;
  555.    send(msg, TYPE_SYNC_DO);
  556.  
  557.    msg = obtain_message();
  558.     msg->data.hook.func = do_set_current;
  559.    msg->data.hook.p.scalar = current;
  560.    send(msg, TYPE_SYNC_DO);
  561.    }
  562.  
  563.  
  564.  
  565.  
  566. /***
  567.  ***
  568.  ***    notice() pseudo-system call.
  569.  ***    mostly used to report errors
  570.  ***
  571.  ***    The only difficulty comes from the fact
  572.  ***    that we may be called under any kind of environment
  573.  ***
  574.  ***/
  575.  
  576. #ifdef USE_ARQ
  577. #include "arq.h"
  578. /* arq 1.78 doesn't notice BuildEasyRequest().
  579.    I need to contact Martin Laubach about it
  580.        FidoNet: 2:310/3.14 
  581.        Usenet:  mjl@alison.at (home) 
  582.                                mjl@auto.tuwien.ac.at (work) 
  583.                 {cbmvax!cbmehq,mcsun!tuvie}!cbmvie!alison!mjl 
  584.  
  585.        Peter, the graphics and animation wizard, can be reached
  586.      2:310/42 in FidoNet.  
  587.  */
  588.  
  589. LOCAL struct ExtEasyStruct es =
  590.    {
  591.    0,
  592.    0,
  593.    ARQ_ID_INFO,
  594.    0,
  595.    ARQ_MAGIC,
  596.    0, 0, 0,
  597.    sizeof(struct EasyStruct),
  598.    0,
  599.    "Notice\xa0",
  600.    NULL,
  601.    "Proceed"
  602.    };
  603. LOCAL struct EasyStruct *esp = & (es.Easy);
  604. #else
  605. LOCAL struct EasyStruct es = 
  606.    {
  607.    sizeof(struct EasyStruct),
  608.    0,
  609.    "Notice",
  610.    NULL,
  611.    "Proceed"
  612.    };
  613. LOCAL struct EasyStruct *esp = &es;
  614. #endif
  615.  
  616.  
  617. void handle_notice(struct Window *w)
  618.    {
  619.    if (SysReqHandler(w, 0, FALSE) != -2)
  620.       {
  621.       remove_signal_handler(w->UserPort->mp_SigBit);
  622.       FreeSysRequest(w);
  623.       notice_win = 0;
  624.       }
  625.    }
  626.  
  627. void notice(char *s)
  628.    {
  629.    INIT_ONCE;
  630.    
  631.    if (!IntuitionBase)
  632.       {
  633.       fprintf(stderr, s);
  634.       fputc('\n', stderr);
  635.       }
  636.    else
  637.       {
  638.          /* wait for previous notice to go away */
  639.       while (notice_win)
  640.          await_events();
  641.       
  642.       esp->es_TextFormat = s;
  643.       notice_win = BuildEasyRequest(0, esp, NULL, NULL);
  644.       install_signal_handler(notice_win->UserPort->mp_SigBit, handle_notice, notice_win);
  645.       }
  646.    }
  647.  
  648.